import React, { useRef, useEffect } from 'react';
import * as THREE from 'three';

const ThreeJSTankAnimation = () => {
  const mountRef = useRef(null); // ref获取DOM容器引用

  useEffect(() => {
    // 一：three.js初始化
    const canvas = mountRef.current;
    const renderer = new THREE.WebGLRenderer({ canvas });
    renderer.setClearColor(0xaaaaaa);
    renderer.shadowMap.enabled = true; // 阴影

    // 相机工厂函数
    const makeCamera = (fov = 40) => {
      const aspect = 2; // the canvas default
      const zNear = 0.1;
      const zFar = 1000;
      return new THREE.PerspectiveCamera(fov, aspect, zNear, zFar);
    };

    const camera = makeCamera();
    camera.position.set(8, 4, 10).multiplyScalar(3);
    camera.lookAt(0, 0, 0);

    const scene = new THREE.Scene();

    //二： 设置光源（光照和阴影效果）
    const mainLight = new THREE.DirectionalLight(0xffffff, 1); // （颜色，强度）
    mainLight.position.set(0, 20, 0);
    scene.add(mainLight);
    mainLight.castShadow = true; // 启用光源阴影投射功能
    mainLight.shadow.mapSize.width = 2048; // 设置阴影分辨率
    mainLight.shadow.mapSize.height = 2048;

    // 定义阴影相机的视锥体范围,形成一个100x100单位的正方形区域(d=50),只有在此区域内的物体才会投射阴影
    const d = 50;
    mainLight.shadow.camera.left = -d;
    mainLight.shadow.camera.right = d;
    mainLight.shadow.camera.top = d;
    mainLight.shadow.camera.bottom = -d;

    mainLight.shadow.camera.near = 1; // 最近渲染距离(1单位)
    mainLight.shadow.camera.far = 50; // 最远渲染距离
    mainLight.shadow.bias = 0.001; // 阴影偏移量
    // 辅助光源，斜向照明，增强场景立体感
    const secondaryLight = new THREE.DirectionalLight(0xffffff, 1);
    secondaryLight.position.set(1, 2, 4);
    scene.add(secondaryLight);

    // 三：地面
    const groundGeometry = new THREE.PlaneGeometry(50, 50);
    const groundMaterial = new THREE.MeshPhongMaterial({ color: 0xcc8866 });
    const groundMesh = new THREE.Mesh(groundGeometry, groundMaterial);
    groundMesh.rotation.x = Math.PI * -0.5;
    groundMesh.receiveShadow = true; // 启用阴影接收功能,使其他物体投射的阴影可以显示在地面上
    scene.add(groundMesh);

    // 四：坦克
    const carWidth = 4;
    const carHeight = 1;
    const carLength = 8;

    // 容器
    const tank = new THREE.Object3D();
    scene.add(tank);

    // 车身
    const bodyGeometry = new THREE.BoxGeometry(carWidth, carHeight, carLength);
    const bodyMaterial = new THREE.MeshPhongMaterial({ color: 0x6688aa });
    const bodyMesh = new THREE.Mesh(bodyGeometry, bodyMaterial);
    bodyMesh.position.y = 1.4;
    bodyMesh.castShadow = true;
    tank.add(bodyMesh);

    // 坦克相机(追尾视角)
    const tankCameraFov = 75;
    const tankCamera = makeCamera(tankCameraFov);
    tankCamera.position.y = 3;
    tankCamera.position.z = -6;
    tankCamera.rotation.y = Math.PI;
    bodyMesh.add(tankCamera); // 将相机附加到车身上,会随车身一起移动旋转

    // 车轮
    const wheelRadius = 1; // 半径=1单位
    const wheelThickness = 0.5; // 厚度=0.5单位
    const wheelSegments = 6; // 6边形轮毂(性能优化)
    const wheelGeometry = new THREE.CylinderGeometry(
      wheelRadius, // 顶部半径
      wheelRadius, // 底部半径
      wheelThickness, // 高度(实际是轮子厚度)
      wheelSegments // 分段数
    );
    const wheelMaterial = new THREE.MeshPhongMaterial({ color: 0x888888 });
    // 车轮的位置
    const wheelPositions = [
      [-carWidth / 2 - wheelThickness / 2, -carHeight / 2, carLength / 3],
      [carWidth / 2 + wheelThickness / 2, -carHeight / 2, carLength / 3],
      [-carWidth / 2 - wheelThickness / 2, -carHeight / 2, 0],
      [carWidth / 2 + wheelThickness / 2, -carHeight / 2, 0],
      [-carWidth / 2 - wheelThickness / 2, -carHeight / 2, -carLength / 3],
      [carWidth / 2 + wheelThickness / 2, -carHeight / 2, -carLength / 3],
    ];
    const wheelMeshes = wheelPositions.map((position) => {
      const mesh = new THREE.Mesh(wheelGeometry, wheelMaterial);
      mesh.position.set(...position);
      mesh.rotation.z = Math.PI * 0.5;
      mesh.castShadow = true;
      bodyMesh.add(mesh);
      return mesh;
    });

    // 坦克炮塔的穹顶部分
    const domeRadius = 2;
    const domeWidthSubdivisions = 12; // 经度分段数
    const domeHeightSubdivisions = 12; // 纬度分段数
    const domePhiStart = 0; // 水平起始角(0°)
    const domePhiEnd = Math.PI * 2; // 水平结束角(360°)
    const domeThetaStart = 0; // 垂直起始角(0°)
    const domeThetaEnd = Math.PI * 0.5; // 垂直结束角(90°)（半球）
    // 创建了一个1/2球体(半径,宽度分段(经线),高度分段(纬线),4-7. 球面裁剪参数)
    const domeGeometry = new THREE.SphereGeometry(
      domeRadius,
      domeWidthSubdivisions,
      domeHeightSubdivisions,
      domePhiStart,
      domePhiEnd,
      domeThetaStart,
      domeThetaEnd
    );
    const domeMesh = new THREE.Mesh(domeGeometry, bodyMaterial);
    domeMesh.castShadow = true;
    bodyMesh.add(domeMesh);
    domeMesh.position.y = 0.5;

    // 炮管
    const turretWidth = 0.1; // 炮塔基座宽度
    const turretHeight = 0.1; // 炮塔基座高度
    const turretLength = carLength * 0.75 * 0.2; // 炮管长度计算
    const turretGeometry = new THREE.BoxGeometry(
      turretWidth,
      turretHeight,
      turretLength
    );
    const turretPivot = new THREE.Object3D(); // 旋转基座
    const turretMesh = new THREE.Mesh(turretGeometry, bodyMaterial);
    turretMesh.castShadow = true;
    turretPivot.scale.set(5, 5, 5);
    turretPivot.position.y = 0.5;
    turretMesh.position.z = turretLength * 0.5;
    turretPivot.add(turretMesh);
    bodyMesh.add(turretPivot);

    // Turret camera
    const turretCamera = makeCamera();
    turretCamera.position.y = 0.75 * 0.2;
    turretMesh.add(turretCamera);

    // 五：目标物体
    const targetGeometry = new THREE.SphereGeometry(0.5, 6, 3);
    const targetMaterial = new THREE.MeshPhongMaterial({
      color: 0x00ff00,
      flatShading: true,
    });
    const targetMesh = new THREE.Mesh(targetGeometry, targetMaterial);

    const targetOrbit = new THREE.Object3D(); // 根节点，控制水平面旋转运动,直接挂载到场景，独立于坦克体系
    const targetElevation = new THREE.Object3D(); // 高度控制
    const targetBob = new THREE.Object3D(); // 空节点，预留用于上下浮动动画
    targetMesh.castShadow = true;
    scene.add(targetOrbit);
    targetOrbit.add(targetElevation);
    targetElevation.position.z = carLength * 2;
    targetElevation.position.y = 8;
    targetElevation.add(targetBob);
    targetBob.add(targetMesh);

    // Target camera
    const targetCamera = makeCamera();
    const targetCameraPivot = new THREE.Object3D();
    targetCamera.position.y = 1;
    targetCamera.position.z = -2;
    targetCamera.rotation.y = Math.PI;
    targetBob.add(targetCameraPivot);
    targetCameraPivot.add(targetCamera);

    // 六：运动路径
    const curve = new THREE.SplineCurve([
      new THREE.Vector2(-10, 0), // 起点
      new THREE.Vector2(-5, 5), // 第一个高点
      new THREE.Vector2(0, 0), // 回中点
      new THREE.Vector2(5, -5), // 第一个低点
      new THREE.Vector2(10, 0), // 右顶点
      new THREE.Vector2(5, 10), // 右上高峰
      new THREE.Vector2(-5, 10), // 左上高峰
      new THREE.Vector2(-10, -10), // 左下低谷
      new THREE.Vector2(-15, -8), // 左外点
      new THREE.Vector2(-10, 0), // 闭合回起点
    ]);

    const points = curve.getPoints(50); //将连续曲线离散为50个点
    const geometry = new THREE.BufferGeometry().setFromPoints(points); // setFromPoints：自动从Vector2数组生成顶点创建几何体
    const material = new THREE.LineBasicMaterial({ color: 0xff0000 });
    const splineObject = new THREE.Line(geometry, material);
    splineObject.rotation.x = Math.PI * 0.5;
    splineObject.position.y = 0.05;
    scene.add(splineObject);

    // 七：自适应屏幕
    const handleResize = () => {
      const canvas = renderer.domElement;
      const width = canvas.clientWidth;
      const height = canvas.clientHeight;
      const needResize = canvas.width !== width || canvas.height !== height;
      if (needResize) {
        renderer.setSize(width, height, false);
        // Update all cameras' aspect ratios
        cameras.forEach((cameraInfo) => {
          const camera = cameraInfo.cam;
          camera.aspect = width / height;
          camera.updateProjectionMatrix();
        });
      }
    };

    // Camera array for cycling through views
    const cameras = [
      { cam: camera, desc: 'Detached camera view' },
      { cam: turretCamera, desc: 'Turret view looking at target' },
      { cam: targetCamera, desc: 'Target view looking at tank' },
      { cam: tankCamera, desc: 'Above back of tank view' },
    ];

    // Animation variables
    const targetPosition = new THREE.Vector3();
    const tankPosition = new THREE.Vector2();
    const tankTarget = new THREE.Vector2();

    // 八：动画循环
    let animationId;
    const animate = (time) => {
      time *= 0.001; // Convert to seconds

      // Move target in circular motion with bobbing
      targetOrbit.rotation.y = time * 0.27;
      targetBob.position.y = Math.sin(time * 2) * 4;
      targetMesh.rotation.x = time * 7;
      targetMesh.rotation.y = time * 13;
      targetMaterial.emissive.setHSL((time * 10) % 1, 1, 0.25);
      targetMaterial.color.setHSL((time * 10) % 1, 1, 0.25);

      // Move tank along the spline path
      const tankTime = time * 0.05;
      curve.getPointAt(tankTime % 1, tankPosition);
      curve.getPointAt((tankTime + 0.01) % 1, tankTarget);
      tank.position.set(tankPosition.x, 0, tankPosition.y);
      tank.lookAt(tankTarget.x, 0, tankTarget.y);

      // Make turret face the target
      targetMesh.getWorldPosition(targetPosition);
      turretPivot.lookAt(targetPosition);

      // Make turret camera look at target
      turretCamera.lookAt(targetPosition);

      // Make target camera look at tank
      tank.getWorldPosition(targetPosition);
      targetCameraPivot.lookAt(targetPosition);

      // Rotate wheels
      wheelMeshes.forEach((obj) => {
        obj.rotation.x = time * 3;
      });

      // Cycle through cameras
      const currentCamera = cameras[Math.floor((time * 0.25) % cameras.length)];
      document.getElementById('camera-info').textContent = currentCamera.desc;

      renderer.render(scene, currentCamera.cam);
      animationId = requestAnimationFrame(animate);
    };

    // Start animation
    animate(0);

    // Add event listeners
    window.addEventListener('resize', handleResize);

    // Cleanup function
    return () => {
      window.removeEventListener('resize', handleResize);
      cancelAnimationFrame(animationId);
      renderer.dispose();

      // Dispose of all geometries and materials
      [
        groundGeometry,
        bodyGeometry,
        wheelGeometry,
        domeGeometry,
        turretGeometry,
        targetGeometry,
        geometry,
      ].forEach((geo) => geo.dispose());

      [
        groundMaterial,
        bodyMaterial,
        wheelMaterial,
        targetMaterial,
        material,
      ].forEach((mat) => {
        if (mat.dispose) mat.dispose();
      });
    };
  }, []);

  return (
    <div style={{ width: '100%', height: '100vh', position: 'relative' }}>
      <canvas
        ref={mountRef}
        style={{ width: '100%', height: '100%', display: 'block' }}
      />
      <div
        id="camera-info"
        style={{
          position: 'absolute',
          top: '20px',
          left: '20px',
          color: 'white',
          backgroundColor: 'rgba(0,0,0,0.5)',
          padding: '10px',
          borderRadius: '5px',
          fontFamily: 'Arial, sans-serif',
        }}
      >
        Camera view information will appear here
      </div>
    </div>
  );
};

export default ThreeJSTankAnimation;
